/*
	http://www.catch22.net/tuts/custom-controls
*/
#include "WaveViewer.h"

TCHAR WaveViewer::szClassName[] = _T("WaveViewCtrl");

WaveViewer::WaveViewer(void){

	x = -1;
}

WaveViewer::WaveViewer(HWND hw){
	this->hwnd = hw;
	this->bgColor = GetSysColor(COLOR_WINDOW);
	this->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);

	x = -1;
	xp = -1;
	yp = -1;
}

WaveViewer::~WaveViewer(void){
}

void WaveViewer::setXY(int _y){
	xp = x;
	yp = y;

	x += 10;
	if(x > coord.right)
		x = 0; //xu ly dich phai

	y = _y;
}

void WaveViewer::releaseBufferDC()
{
	if(hbmpBuffer != NULL)
	{
		SelectObject(memoryDC, oldBmp);
		SelectObject(memoryDC, oldPen);
		DeleteObject(hbmpBuffer);
		DeleteDC(memoryDC);
		DeleteObject(bgbrush);
		DeleteObject(hPen);
	}
}

void WaveViewer::onSizeChanged(HWND hwnd, WPARAM wparam, LPARAM lparam)
{
	RECT clientRect;
	int height = HIWORD(lparam);
	int width = LOWORD(lparam);
	coord.setViewport(0, 0, width, height);
	coord.setScale(.1f, .1f);
	coord.moveTo(15, height/3);

	releaseBufferDC();
	HDC hdc = GetDC(hwnd);
	hbmpBuffer = CreateCompatibleBitmap(hdc, coord.right - coord.left, coord.bottom - coord.top);
	memoryDC = CreateCompatibleDC(hdc);

	bgbrush = CreateSolidBrush(RGB(200, 200, 200));
	oldBrush = (HBRUSH)SelectObject(memoryDC, bgbrush);
	hPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 255));
	oldBmp = (HBITMAP)SelectObject(memoryDC, hbmpBuffer);
	oldPen = (HPEN)SelectObject(memoryDC, hPen);


	FillRect(memoryDC, &clientRect, bgbrush);
	ReleaseDC(hwnd, hdc);
}

void WaveViewer::paint(HWND hwnd)
{
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hwnd, &ps);	

	//MoveToEx(memoryDC, 10, 100, NULL);
	//SetPixel(memoryDC,10, 100, color);
	//LineTo(memoryDC, 20, 200);

	//do paint on memoryDC here
	
	//1. paint coordinator
	coord.draw(memoryDC);
	if(xp < 0){
		MoveToEx(memoryDC, x, y, NULL);
		SetPixel(memoryDC,x, y, color);
	}
	else{
		LineTo(memoryDC, x, y);
	}
	
	//copy from buffer DC to "real" DC
	BitBlt(hdc, 0, 0, coord.right - coord.left, coord.bottom - coord.top, memoryDC, 0, 0, SRCCOPY);
	EndPaint(hwnd, &ps);
}

/* ===================================================================================================== */

HWND createWaveWindow(HWND parent, HINSTANCE hInst){
	HINSTANCE h = GetModuleHandle(0);

	return CreateWindowEx(WS_EX_CLIENTEDGE,
							WaveViewer::szClassName,
							_T(""),
							WS_VISIBLE | WS_CHILD|WS_BORDER,
							0, 0, 100, 100,
							parent,
							NULL,
							//GetModuleHandle(0),
							hInst,
							NULL);
	
	/*
	return CreateWindow(WaveViewer::szClassName,
							_T("TEST"),
							WS_BORDER | WS_CHILD | WS_VISIBLE,
							CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
							parent,
							NULL,
							GetModuleHandle(0),
							NULL);*/
}


/* Global functions */
WaveViewer* getWaveViewerObjectFromWindow(HWND hwnd)
{
	return (WaveViewer*)GetWindowLong(hwnd, GWL_USERDATA);
}


float my_conv(float v){
	float r;
	unsigned char *dst = (unsigned char *)&r;
	unsigned char *src = (unsigned char *)&v;

	dst[3] = src[3];
	dst[2] = src[2];
	dst[1] = src[1];
	dst[0] = src[0];

	return r;
}

LRESULT CALLBACK waveViewerProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam){

	WaveViewer* view = getWaveViewerObjectFromWindow(hwnd);
	short value;
	float fvalue;
	switch(msg){
		case WM_NCCREATE:
			view = new WaveViewer(hwnd);
			if(view == NULL)
				return FALSE;

			SetWindowLong(hwnd, GWL_USERDATA, (LONG)view);

			return TRUE;

		case WM_PAINT:
			view->paint(hwnd);
			break;

		case WM_ERASEBKGND:
			return TRUE;

		case WM_SIZE:
			view->onSizeChanged(hwnd, wparam, lparam);
			break;

		case WV_RECEIVE:
			/*
				value = *((int*)(lparam));
				if(value < view->coord.top)
					value = view->coord.top + 1;
				else
					if(value > view->coord.bottom)
						value = view->coord.bottom - 1;
			*/
			value = *((short*)(lparam));
			//value = my_conv(value);
			//view->setXY(value);
			fvalue = value * (3.3/4096);
			view->coord.addValue(fvalue);
			InvalidateRect(hwnd, NULL, FALSE);
			break;

		case WM_NCDESTROY:
			delete view;
			break;

		default:
			return DefWindowProc(hwnd, msg, wparam, lparam);
	}

	//return DefWindowProc(hwnd, msg, wparam, lparam);
	return TRUE;
}

BYTE registerWaveViewerClass(HINSTANCE hInst)
{
	WNDCLASSEX wndcls;

	if (GetClassInfoEx(NULL, WaveViewer::szClassName, &wndcls))
        return 1;

	wndcls.cbSize        = sizeof(WNDCLASSEX);
	wndcls.style         = CS_HREDRAW | CS_VREDRAW;//CS_GLOBALCLASS;;
	wndcls.lpfnWndProc   = (WNDPROC)waveViewerProc;
	wndcls.cbClsExtra    = NULL;
	wndcls.cbWndExtra    = NULL;
	wndcls.hIcon         = NULL;//LoadIcon(NULL, IDI_APPLICATION);
	wndcls.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndcls.lpszMenuName  = NULL;
	wndcls.lpszClassName = WaveViewer::szClassName;
	wndcls.hInstance     = hInst; 
	wndcls.hIconSm       = NULL;//LoadIcon(NULL, IDI_APPLICATION);

	return RegisterClassEx(&wndcls);
}